(* ===================================================================== *)
(** Dispaly : Affichage avec chaine de format : entiers ou bits 
    @author Mathieu Barbin
    @date samedi 3 janvier 2009, 23:30:18 (UTC+0100) *)
(* ===================================================================== *)

  (** Exception si le format est incorrect, ou les arguments trop courts *)
  exception FormatError of string
  
    
  type print_value = PrintBit of int | PrintInt of int | PrintSignedInt of int

  (** etant donnee une chaine st, un index strict max, et un pointeur p de depart, donne le plus long nombre
      contenu dans st a partir de p *)
  let int_in_string s max p =
    let rec aux accu i =
      let stop () = if accu = "" then (None, i) else ((Some (int_of_string accu)), i) in
      if i >= max
      then stop ()
      else 
	let cchar = int_of_char s.[i] in
	if cchar >= 48 && cchar <= 57 
	then aux (Printf.sprintf "%s%c" accu s.[i]) (succ i)
	else stop ()
    in aux "" p;;
	


  (** Etant donnee une chaine et un pointeur sur un caractere '%' on donne le nombre et 
      le type, et l'indice suivant *)
  let print_value_of_index st len ind =
    if ind >= pred len || st.[ind] <> '%'
    then raise (FormatError "")
    else
      let num, next = int_in_string st len (succ ind) in
      if next >= len
      then raise (FormatError "")
      else
	let typ = 
	  match st.[next], num with
	  | 'n', None -> PrintInt 1
	  | 'n', Some d -> PrintInt d
	  | 'd', None -> PrintSignedInt 1
	  | 'd', Some d -> PrintSignedInt d	      
	  | 'b', None -> PrintBit 1
	  | 'b', Some d -> PrintBit d
	  | o, _ -> raise (FormatError (Printf.sprintf "Format '%c%c' is not supported" '%' o)) 
	in typ, succ next
      

  (** Etant donnee une chaine de format, et des bits, on produit une chaine *)
  let sprintf format booltab =
    let lenbooltab = Array.length booltab in
    let indexbool = ref 0 in
    let len = String.length format in
    let rec aux accu i =
      if i >= len
      then accu
      else
	if format.[i] = '%'
	then
	  let typ, next = print_value_of_index format len i in
	  match typ with
	  | PrintInt d ->
	      let tmp = Array.make d false in
	      if !indexbool + d > lenbooltab
	      then raise (FormatError "Too few Arguments")
	      else
		begin
		  Array.blit booltab (!indexbool) tmp 0 d;
		  indexbool := !indexbool + d;
		  aux (Printf.sprintf "%s%d" accu (BoolArray.to_int tmp)) next
		end
	  | PrintSignedInt d ->
	      let tmp = Array.make d false in
	      if !indexbool + d > lenbooltab
	      then raise (FormatError "Too few Arguments")
	      else
		begin
		  Array.blit booltab (!indexbool) tmp 0 d;
		  indexbool := !indexbool + d;
		  aux (Printf.sprintf "%s%d" accu (BoolArray.to_signed_int tmp)) next
		end	  
	  | PrintBit d ->
	      let tmp = Array.make d false in
	      if !indexbool + d > lenbooltab
	      then raise (FormatError "Too few Arguments")
	      else
		begin
		  Array.blit booltab (!indexbool) tmp 0 d;
		  indexbool := !indexbool + d;
		  aux (Printf.sprintf "%s%s" accu (BoolArray.to_string tmp)) next
		end
	else aux (Printf.sprintf "%s%c" accu format.[i]) (succ i)
    in aux "" 0

